﻿using System;
using System.Collections.Generic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Dysmsapi.Model.V20170525;
using DTcms.Common;

namespace DTcms.SMS.Aliyun
{
    /// <summary>
    /// 阿里云
    /// 2019-7-2
    /// https://account.aliyun.com
    /// </summary>
    public class AliSms : ISms
    {
        /// <summary>
        /// 参数配置
        /// </summary>
        private AliYunSmsSetting setting=new AliYunSmsSetting();

        /// <summary>
        /// 同一手机单日最大允许发送量
        /// </summary>
        private readonly int sendCount;

        /// <summary>
        /// 同一IP地址，单日最大允许提交请求次数
        /// </summary>
        private readonly int ipCount;

        /// <summary>
        /// 平台单日发送上限
        /// </summary>
        private readonly int safeTotal;

        /// <summary>
        /// 实例化
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="secret">secret</param>
        /// <param name="sign">签名</param>
        /// <param name="sendCount">同一手机单日最大允许发送量</param>
        /// <param name="ipCount">同一IP地址，单日最大允许提交请求次数</param>
        /// <param name="safeTotal">平台单日发送上限</param>
        public AliSms(string key, string secret, string sign, int sendCount, int ipCount, int safeTotal)
        {
            if (!string.IsNullOrEmpty(key))
            {
                setting.AccessKeyId = key;
            }
            if (!string.IsNullOrEmpty(secret))
            {
                setting.AccessKeySecret = DESEncrypt.Decrypt(secret);
            }
            else
            {
                setting.AccessKeySecret = string.Empty;
            }
            setting.SignName = sign;
            this.sendCount = sendCount;
            this.ipCount = ipCount;
            this.safeTotal = safeTotal;
        }

        /// <summary>
        /// 发送手机短信 单条
        /// </summary>
        /// <param name="mobile">手机号码，以英文“,”逗号分隔开</param>
        /// <param name="templateId">短信模板编号</param>
        /// <param name="pass">无作用（备用）</param>
        /// <param name="msg">返回提示信息</param>
        /// <param name="paramJsonString">关键词替换  用于替换模板中的关键词，采用Json格式,如：{"code":"123456"}</param>
        /// <returns>bool</returns>
        public bool Send(string mobiles, string templateId, int pass, string paramJsonString, out string msg)
        {
            if (string.IsNullOrEmpty(setting.AccessKeyId) || string.IsNullOrEmpty(setting.AccessKeySecret) || string.IsNullOrEmpty(setting.SignName))
            {
                msg = "短信配置参数有误，请完善后再提交！";
                return false;
            }
            //验证手机号码
            if (!Utils.IsMobilePhone(mobiles))
            {
                msg = "手机号码格式不正确！";
                return false;
            }
            if (string.IsNullOrEmpty(templateId))
            {
                msg = "短信模板编号不能为空！";
                return false;
            }

            bool status = true;
            BLL.sms_log bll = new BLL.sms_log();
            //查询是否超出平台限制
            int thisSafeTotal = bll.GetCurDayCount();
            if (this.safeTotal > 0 && thisSafeTotal > this.safeTotal)
            {
                msg = "对不起，平台短信发送量已超出最大限制！";
                return false;
            }

            //查询当前IP是否已经超出限制
            string ip = DTRequest.GetIP();
            int thisIpSendCount = bll.GetIPCount(ip);
            if (this.ipCount > 0 && thisIpSendCount > this.ipCount)
            {
                msg = "对不起，你的网络已经超出发送数量限制！";
                return false;
            }

            msg = string.Empty;
            if (status)
            {
                //发送短信
                Model.sms_log model = new Model.sms_log();
                model.mobile = mobiles;
                model.content = templateId;
                model.send_time = DateTime.Now;
                try
                {
                    bool flag3 = string.IsNullOrEmpty(paramJsonString);
                    if (flag3)
                    {
                        paramJsonString = "{}";
                    }
                    paramJsonString = paramJsonString.Trim();
                    bool flag4 = paramJsonString.IndexOf("{") != 0 || paramJsonString.IndexOf("}") != paramJsonString.Length - 1;
                    if (flag4)
                    {
                        msg = "paramJsonString参数必须为Json格式字符串";
                        return false;
                    }
                    else
                    {
                        string product = "Dysmsapi";
                        string domain = "dysmsapi.aliyuncs.com";
                        string accessKeyId = setting.AccessKeyId;
                        string accessKeySecret = setting.AccessKeySecret;
                        string signName = setting.SignName;

                        IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", accessKeyId, accessKeySecret);
                        DefaultProfile.AddEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
                        IAcsClient acsClient = new DefaultAcsClient(profile);
                        SendSmsRequest sendSmsRequest = new SendSmsRequest();

                        sendSmsRequest.PhoneNumbers = mobiles;
                        sendSmsRequest.SignName = signName;
                        sendSmsRequest.TemplateCode = templateId;
                        sendSmsRequest.TemplateParam = paramJsonString;
                        sendSmsRequest.OutId = "";
                        SendSmsResponse acsResponse = acsClient.GetAcsResponse<SendSmsResponse>(sendSmsRequest);
                        bool flag6 = acsResponse.Code.Equals("ok", StringComparison.OrdinalIgnoreCase);
                        if (flag6)
                        {
                            model.status = 0;
                            model.remark = acsResponse.Message;
                        }
                        else
                        {
                            model.status = 1;
                            model.remark = acsResponse.Code + ":" + acsResponse.Message; 
                        }
                    }
                }
                catch (Exception ex)
                {
                    status = false;
                    model.status = 1;
                    model.remark = "提交失败，错误提示：" + ex.Message;
                    msg = model.remark;
                }
                bll.Add(model);
            }

            //返回状态
            if (status)
            {
                msg = "发送成功！";
                return true;
            }
            return false;
        }

        /// <summary>
        /// 手机短信（批量发送）
        /// 注意：批量发送只验证平台发送总数限制；
        /// </summary>
        /// <param name="mobiles">手机号码，以英文“,”逗号分隔开</param>
        /// <param name="content">短信模板编号</param>
        /// <param name="pass">无作用（备用）</param>
        /// <param name="msg">返回提示信息</param>
        /// <param name="paramJsonString">关键词替换  用于替换模板中的关键词，采用Json格式,如：{"code":"123456"}</param>
        /// <returns>bool</returns>
        public bool MultiSend(string mobiles, string templateId, int pass, string paramJsonString, out string msg)
        {
            if (string.IsNullOrEmpty(setting.AccessKeyId) || string.IsNullOrEmpty(setting.AccessKeySecret) || string.IsNullOrEmpty(setting.SignName))
            {
                msg = "短信配置参数有误，请完善后再提交！";
                return false;
            }
            if (string.IsNullOrEmpty(templateId))
            {
                msg = "短信模板编号不能为空！";
                return false;
            }
            int sucCount = 0;
            string[] oldMobileArr = mobiles.Split(',');

            BLL.sms_log bll = new BLL.sms_log();
            //查询是否超出平台限制
            int thisSafeTotal = bll.GetCurDayCount();
            if (this.safeTotal > 0 && thisSafeTotal > this.safeTotal)
            {
                msg = "对不起，平台短信发送量已超出最大限制！";
                return false;
            }
            //错误消息
            string errorMsg = string.Empty;

            //2000条为一批，求出分多少批
            int batch = oldMobileArr.Length / 2000 + 1;
            for (int i = 0; i < batch; i++)
            {
                StringBuilder sb = new StringBuilder();
                int sendCount = 0; //发送数量
                int maxLenght = (i + 1) * 2000; //循环最大的数

                //检测号码，忽略不合格的，重新组合
                for (int j = 0; j < oldMobileArr.Length && j < maxLenght; j++)
                {
                    int arrNum = j + (i * 2000);
                    string mobile = oldMobileArr[arrNum].Trim();
                    if (!Utils.IsMobilePhone(mobile))//验证手机号码
                    {
                        sendCount++;
                        sb.Append(mobile + ",");
                    }
                }

                //发送短信
                if (sb.ToString().Length > 0)
                {
                    try
                    {
                        bool flag3 = string.IsNullOrEmpty(paramJsonString);
                        if (flag3)
                        {
                            paramJsonString = "{}";
                        }
                        paramJsonString = paramJsonString.Trim();
                        bool flag4 = paramJsonString.IndexOf("{") != 0 || paramJsonString.IndexOf("}") != paramJsonString.Length - 1;
                        if (flag4)
                        {
                            msg = "paramJsonString参数必须为Json格式字符串";
                            return false;
                        }
                        else
                        {
                            string product = "Dysmsapi";
                            string domain = "dysmsapi.aliyuncs.com";
                            string accessKeyId = setting.AccessKeyId;
                            string accessKeySecret = setting.AccessKeySecret;
                            string signName = setting.SignName;

                            IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", accessKeyId, accessKeySecret);
                            DefaultProfile.AddEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
                            IAcsClient acsClient = new DefaultAcsClient(profile);
                            SendSmsRequest sendSmsRequest = new SendSmsRequest();

                            sendSmsRequest.PhoneNumbers = Utils.DelLastComma(sb.ToString());
                            sendSmsRequest.SignName = signName;
                            sendSmsRequest.TemplateCode = templateId;
                            sendSmsRequest.TemplateParam = paramJsonString;
                            sendSmsRequest.OutId = "";
                            SendSmsResponse acsResponse = acsClient.GetAcsResponse<SendSmsResponse>(sendSmsRequest);
                            bool flag6 = acsResponse.Code.Equals("ok", StringComparison.OrdinalIgnoreCase);
                            if (flag6)
                            {
                                sucCount++;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        errorMsg = "提交失败，错误提示：" + ex.Message;
                    }
                }
            }
            //返回状态
            if (sucCount > 0)
            {
                msg = "成功提交" + sucCount + "条，失败" + (oldMobileArr.Length - sucCount) + "条";
                return true;
            }
            msg = errorMsg;
            return false;
        }

        /// <summary>
        /// 查询账户剩余短信数量
        /// </summary>
        public string GetAccountQuantity()
        {
            return "没有提供查询接口";
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;
        }

        /// <summary>
        /// 错误列表
        /// </summary>
        /// <returns></returns>
        private Dictionary<string, string> ErrorDic()
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("isv.OUT_OF_SERVICE", "登陆www.alidayu.com充值");
            dic.Add("isv.PRODUCT_UNSUBSCRIBE", " 登陆www.alidayu.com开通相应的产品服务");
            dic.Add("isv.ACCOUNT_NOT_EXISTS", "登陆www.alidayu.com完成入驻");
            dic.Add("isv.ACCOUNT_ABNORMAL", "联系技术支持");
            dic.Add("isv.SMS_TEMPLATE_ILLEGAL", "登陆www.alidayu.com查询审核通过短信模板使用");
            dic.Add("isv.SMS_SIGNATURE_ILLEGAL", "登陆www.alidayu.com查询审核通过的签名使用");
            dic.Add("isv.MOBILE_NUMBER_ILLEGAL", "使用合法的手机号码");
            dic.Add("isv.MOBILE_COUNT_OVER_LIMIT", "批量发送，手机号码以英文逗号分隔，不超过200个号码");
            dic.Add("isv.TEMPLATE_MISSING_PARAMETERS", "确认短信模板中变量个数，变量名，检查传参是否遗漏");
            dic.Add("isv.INVALID_PARAMETERS", "检查参数是否合法");
            dic.Add("isv.BUSINESS_LIMIT_CONTROL", "短信验证码，使用同一个签名，对同一个手机号码发送短信验证码，支持1条 / 分钟，5条 / 小时，10条 / 天。一个手机号码通过阿里大于平台只能收到40条 / 天。 短信通知，使用同一签名、同一模板，对同一手机号发送短信通知，允许每天50条（自然日）。");
            dic.Add("isv.INVALID_JSON_PARAM", "JSON参数接受字符串值。例如{ \"code\":\"123456\"}，不接收{ \"code\":123456}");
            dic.Add("isp.SYSTEM_ERROR", "-");
            dic.Add("isv.BLACK_KEY_CONTROL_LIMIT", "如：阿里大鱼 黑名单关键字禁止在模板变量中使用，若业务确实需要使用，建议将关键字放到模板中，进行审核。");
            dic.Add("isv.PARAM_NOT_SUPPORT_URL", " 域名和ip请固化到模板申请中");
            dic.Add("isv.PARAM_LENGTH_LIMIT", "变量长度受限 请尽量固化变量中固定部分");
            dic.Add("isv.AMOUNT_NOT_ENOUGH", "因余额不足未能发送成功，请登录管理中心充值后重新发送");
            dic.Add("isv.DAY_LIMIT_CONTROL", "修改日发送量限额值");
            dic.Add("isv.MONTH_LIMIT_CONTROL", "修改月发送量限额值");
            dic.Add("isv.SMS_SIGN_ILLEGAL", "检查短信发送时使用的签名");
            return dic;
        }
    }
}
